#include "DataFlow.h"
#include <map>

using namespace std;

typedef char Type_Type;
typedef unsigned short Type_Length;
typedef DataFlow Type_Value;

class TLVpacketer : public DataFlow, public map<Type_Type, Type_Value>
{
public:
    TLVpacketer() : DataFlow() { }
    TLVpacketer(const DataFlow d) : DataFlow(d)
    {
        ParsePacket();
    }
    TLVpacketer(const char* buffer, unsigned int length) :
        DataFlow(buffer, length)
    {
        ParsePacket();
    }

    void MakePacket()
    {
        TLVpacketer :: iterator it;
        int len_value = 0, available_tlv = 0;
        ClearBuffer();
        for ( it = begin() ; it != end(); it++ )
        {
            if (it->second.GetLength() > 0)
            {
                len_value += it->second.GetLength();
                available_tlv++;
            }
        }
        if (len_value > 0)
        {
            BufferLength = (sizeof(Type_Type) + sizeof(Type_Length)) * available_tlv
                           + len_value;
            Buffer = new char[BufferLength];
            char *t = Buffer;
            for ( it = begin() ; it != end(); it++ )
            {
                if (it->second.GetLength() > 0)
                {
                    *(Type_Type *)t = it->first;
                    t += sizeof(Type_Type);
                    *(Type_Length *)t = it->second.GetLength();
                    t += sizeof(Type_Length);
                    memcpy(t, it->second.GetData(), it->second.GetLength());
                    t += it->second.GetLength();
                }
            }
        }
    }
    int ParsePacket()
    {
        Type_Type type;
        Type_Length length;
        int remain_length = BufferLength;
        char *t = Buffer;

        map::clear();
        while (remain_length > 0)
        {
            remain_length -= (sizeof(Type_Type) + sizeof(Type_Length));
            if (remain_length < 0) break;  // remain_length == 0 if no value
            type = *(Type_Type *)t;
            t += sizeof(Type_Type);
            length = *(Type_Length *)t;
            remain_length -= length;
            if (remain_length < 0) break;
            t += sizeof(Type_Length);
            DataFlow value(t, length);
            t += length;
            (*this)[type] = value;
        }
        return size();
    }
};